#include <cassert>
#include <ctime>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <vector>
#include <string>
#include <iostream>
#define MakeSeed() srand((unsigned long)time(nullptr) ^ getpid() ^ 0x171237 ^ rand() % 1234)
#define PROCESS_NUM 10
typedef void (*func_t)();
void downLoadTask()
{
    std::cout << getpid() << " : 下载任务\n"
              << std::endl;
    sleep(1);
}
void ioTask()
{
    std::cout << getpid() << " : IO任务\n"
              << std::endl;
    sleep(1);
}
void flushTask()
{
    std::cout << getpid() << " : 刷新任务\n"
              << std::endl;
    sleep(1);
}
void loadTaskFunc(std::vector<func_t> *out)
{
    assert(out);
    out->push_back(downLoadTask);
    out->push_back(ioTask);
    out->push_back(flushTask);
}
class subEp
{
public:
    subEp(pid_t subId, int writeFd)
        : subId_(subId), writeFd_(writeFd)
    {
        char buffer[1024];
        snprintf(buffer, sizeof(buffer), "process-%d[pid(%d)-fd(%d)]", num_++, subId_, writeFd_);
        name_ = buffer;
    }

public:
    std::string name_;
    pid_t subId_;
    int writeFd_;
    static int num_;
};
int subEp::num_ = 0;
void sendTask(const subEp &process, int taskNum)
{
    std::cout << "send task num : " << taskNum << "send to -> " << process.name_ << std::endl;
    int n = write(process.writeFd_, &taskNum, sizeof(taskNum));
    assert(n == sizeof(int));
    (void)n;
}
int recvTask(int readFd)
{
    int code = 0;
    ssize_t s = read(readFd, &code, sizeof(code));
    if (s == 4)
    {
        return code;
    }
    else if (s <= 0)
    {
        return -1;
    }
    else
    {
        return 0;
    }
}
// 版本1
//  void CreateSubProcess(std::vector<subEp> *subs, std::vector<func_t> &funcMap)
//  {
//      for (int i = 0; i < PROCESS_NUM; i++)
//      {
//          int fds[2];
//          int n = pipe(fds);
//          assert(n == 0);
//          (void)n;
//          pid_t pid = fork();
//          if (pid == 0)
//          {
//              close(fds[1]);
//              while (true)
//              {
//                  int commandCode = recvTask(fds[0]);
//                  if (commandCode >= 0 && commandCode < funcMap.size())
//                  {
//                      funcMap[commandCode]();
//                  }
//                  else if (commandCode == -1)
//                  {
//                      break;
//                  }
//              }
//              exit(0);
//          }
//          close(fds[0]);
//          subEp sub(pid, fds[1]);
//          subs->push_back(sub);
//      }
//  }
// 版本2
void CreateSubProcess(std::vector<subEp> *subs, std::vector<func_t> &funcMap)
{
    std::vector<int> deleteFd;
    for (int i = 0; i < PROCESS_NUM; i++)
    {
        int fds[2];
        int n = pipe(fds);
        assert(n == 0);
        (void)n;
        pid_t pid = fork();
        if (pid == 0)
        {
            for (int i = 0; i < deleteFd.size(); i++)
            {
                close(deleteFd[i]);
            }
            close(fds[1]);
            while (true)
            {
                int commandCode = recvTask(fds[0]);
                if (commandCode >= 0 && commandCode < funcMap.size())
                {
                    funcMap[commandCode]();
                }
                else if (commandCode == -1)
                {
                    break;
                }
            }
            exit(0);
        }
        close(fds[0]);
        subEp sub(pid, fds[1]);
        subs->push_back(sub);
        deleteFd.push_back(fds[1]);
    }
}
void loadBlanceContrl(const std::vector<subEp> &subs, const std::vector<func_t> &funcMap, int count)
{
    int processnum = subs.size();
    int tasknum = funcMap.size();
    bool forever = (count == 0 ? true : false);
    while (true)
    {
        int subIdx = rand() % processnum;
        int taskIdx = rand() % tasknum;
        sendTask(subs[subIdx], taskIdx);
        sleep(1);
        if (!forever)
        {
            count--;
            if (count == 0)
                break;
        }
    }
    for (int i = 0; i < processnum; i++)
    {
        close(subs[i].writeFd_);
    }
}
void waitProcess(std::vector<subEp> subs)
{
    int processnum = subs.size();
    for (int i = 0; i < processnum; i++)
    {
        waitpid(subs[i].subId_, nullptr, 0);
        std::cout << "wait sub process success...: " << subs[i].subId_ << std::endl;
    }
}
int main()
{
    MakeSeed();
    std::vector<func_t> funcMap;
    loadTaskFunc(&funcMap);
    std::vector<subEp> subs;
    CreateSubProcess(&subs, funcMap);
    int taskCnt = 10;
    loadBlanceContrl(subs, funcMap, taskCnt);
    waitProcess(subs);
    return 0;
}